
package com.scs.application.modules.order.service.impl;

import cn.afterturn.easypoi.excel.entity.ImportParams;
import cn.afterturn.easypoi.excel.entity.result.ExcelImportResult;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.google.common.collect.Lists;
import com.scs.application.core.exceptions.BusinessException;
import com.scs.application.core.model.ImportResult;
import com.scs.application.core.service.BaseServiceImpl;
import com.scs.application.core.thread.BatchSaveTask;
import com.scs.application.core.thread.DefaultSaveHandler;
import com.scs.application.core.utils.*;
import com.scs.application.modules.order.consts.DictConsts;
import com.scs.application.modules.order.dto.DeliveryItemAddBySelectDTO;
import com.scs.application.modules.order.dto.DeliveryItemImportDTO;
import com.scs.application.modules.order.dto.DeliveryItemSplitDTO;
import com.scs.application.modules.order.entity.Delivery;
import com.scs.application.modules.order.entity.DeliveryItem;
import com.scs.application.modules.order.entity.PurchaseOrderItem;
import com.scs.application.modules.order.excel.handler.ExportHeadDTO;
import com.scs.application.modules.order.mapper.DeliveryItemMapper;
import com.scs.application.modules.order.mapper.DeliveryMapper;
import com.scs.application.modules.order.mapper.PurchaseOrderItemMapper;
import com.scs.application.modules.order.request.DeliveryItemQueryRequest;
import com.scs.application.modules.order.service.DeliveryItemService;
import com.scs.application.modules.order.service.PurchaseOrderItemService;
import com.scs.application.modules.order.vo.DeliveryItemVO;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.util.CellRangeAddress;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.stream.Collectors;

/**
 * 发货单明细 service 实现
 */
@Slf4j
@Service
@AllArgsConstructor
@Transactional(rollbackFor = Exception.class)
public class DeliveryItemServiceImpl extends BaseServiceImpl<DeliveryItemMapper, DeliveryItem> implements DeliveryItemService {

    private final PurchaseOrderItemMapper purchaseOrderItemMapper;

    @Autowired
    @Lazy
    private PurchaseOrderItemService purchaseOrderItemService;

    private final DeliveryMapper deliveryMapper;


    @Override
    public List<DeliveryItemVO> list(DeliveryItemQueryRequest request) {
        return this.baseMapper.list(request);
    }

    @Override
    public IPage<DeliveryItem> page(DeliveryItemQueryRequest request) {
        IPage page = this.page(request.getPage(), Wrappers.<DeliveryItem>query()
                .eq(request.getDeliveryId() != null, "delivery_id", request.getDeliveryId())
                .orderByDesc("gmt_modified")
        );
        return page;
    }

    @Override
    public List<DeliveryItem> surplusPurchaseOrder(Delivery delivery) {
        //存储materialCode
        List<String> materialCodeList = new ArrayList<>();
        List<PurchaseOrderItem> purchaseOrderItemList = new ArrayList<>();
        if (delivery.getMaterialCodes() != null) {
            String[] strArray = delivery.getMaterialCodes().split(",");
            materialCodeList = Arrays.asList(strArray);
            purchaseOrderItemList = purchaseOrderItemMapper.selectList(Wrappers.<PurchaseOrderItem>query()
                    .eq(delivery.getPoId() != null, "po_id", delivery.getPoId())
                    .in("delivery_status", 0, 1)
                    .notIn("material_code", materialCodeList));
        } else {
            purchaseOrderItemList = purchaseOrderItemMapper.selectList(Wrappers.<PurchaseOrderItem>query()
                    .eq(delivery.getPoId() != null, "po_id", delivery.getPoId())
                    .in("delivery_status", 0, 1));
        }

        List<DeliveryItem> deliveryItemList = new ArrayList<>();

//        采购明细添加到发货明细
        for (PurchaseOrderItem purchaseOrderItem : purchaseOrderItemList) {
            if (purchaseOrderItem.getQty().equals(purchaseOrderItem.getDeliveredQty())) {
                continue;
            }

            DeliveryItem deliveryItem = new DeliveryItem();
            BeanUtils.copyProperties(purchaseOrderItem, deliveryItem);
            deliveryItem.setDeliveryId(delivery.getId())
                    .setShouldDeliveryQty(purchaseOrderItem.getQty())
                    .setDeliveredQty(purchaseOrderItem.getDeliveredQty())
                    .setQty(purchaseOrderItem.getQty() - purchaseOrderItem.getDeliveredQty())
                    .setPoItemId(purchaseOrderItem.getId())
                    .setOrderQty(purchaseOrderItem.getOrderQty())
                    .setOrderUnit(purchaseOrderItem.getOrderUnit())
                    .setId(null);
            deliveryItemList.add(deliveryItem);
        }
        return deliveryItemList;
    }

    @Override
    public boolean saveDeliveryItemsById(DeliveryItem entity) {
        entity.setSubtotalAmount(getRoundDouble(entity.getQty() * entity.getPrice()));
        boolean b = this.save(entity);

        //   修改主表发货金额
        Delivery delivery = new Delivery();
        delivery.setDeliveryAmount(getDeliveryAmount(entity.getDeliveryId())).setId(entity.getDeliveryId());
        deliveryMapper.updateById(delivery);

        return b;
    }

    @Override
    public boolean updateDeliveryItemsById(DeliveryItem entity) {
        //如果发货数量不等于基本数量*比率
        if (entity.getQty() != entity.getDeliveryNumber() * entity.getOrderQty()) {
            entity.setQty(entity.getDeliveryNumber() * entity.getOrderQty());
        }
        entity.setSubtotalAmount(getRoundDouble(entity.getQty() * entity.getPrice()));
        boolean b = this.updateById(entity);

        //   修改主表发货金额
        Delivery delivery = new Delivery();
        delivery.setDeliveryAmount(getDeliveryAmount(entity.getDeliveryId())).setId(entity.getDeliveryId());
        deliveryMapper.updateById(delivery);

        return b;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdateBatchDtl(List<DeliveryItem> newArrayList) {
        //   修改每条明细小计金额
        double deliveryAmount = 0.0;
        Delivery delivery = new Delivery();
        for (DeliveryItem item : newArrayList) {
            //比较发货数量跟基本数量是否匹配
            /*if(item.getQty() != item.getDeliveryNumber()*item.getOrderQty()){
                throw new BusinessException("发货数量跟基本数量不匹配，请检查！");
            }*/
            //如果发货数量不等于基本数量*比率
            if (item.getQty() != item.getDeliveryNumber() * item.getOrderQty()) {
                item.setQty(item.getDeliveryNumber() * item.getOrderQty());
            }
            item.setSubtotalAmount(getRoundDouble(item.getQty() * item.getPrice()));
            deliveryAmount += item.getSubtotalAmount();
            delivery.setId(item.getDeliveryId());
        }

        delivery.setDeliveryAmount(deliveryAmount);
        //   修改主表发货金额
        deliveryMapper.updateById(delivery);

        return this.saveOrUpdateBatch(newArrayList);
    }

    @Override
    public boolean deleteById(String id) {
        DeliveryItem entity = this.getById(id);
        String deliveryId = entity.getDeliveryId();
        boolean b = this.removeCascadeById(id);
        //   修改主表发货金额
        Delivery delivery = new Delivery();
        delivery.setDeliveryAmount(getDeliveryAmount(deliveryId)).setId(deliveryId);
        deliveryMapper.updateById(delivery);


        return b;
    }

    private double getDeliveryAmount(String deliveryId) {
        BigDecimal result = this.getObj(Wrappers.<DeliveryItem>query().
                        select("sum(subtotal_amount)")
                        .eq("delivery_id", deliveryId),
                o -> (BigDecimal) o);
        return result == null ? 0d : result.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    private double getRoundDouble(Double value) {
        if (value == null) {
            return 0d;
        }
        BigDecimal b = new BigDecimal(value);
        return b.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
    }

    @Override
    public IPage<DeliveryItemVO> allDeliveryPage(DeliveryItemQueryRequest request) {
        IPage page = this.baseMapper.deliveryItemPage(request.getPage(), request);
        return page;
    }

    @Override
    public List<DeliveryItem> getExportDeliveryItems(String deliveryId) {
        Delivery delivery = deliveryMapper.selectById(deliveryId);
        if (delivery == null) {
            return null;
        }
        //获取所有未发货完成的采购明细
        List<PurchaseOrderItem> purchaseOrderItemList = purchaseOrderItemMapper.selectList(Wrappers.<PurchaseOrderItem>query()
                .eq("po_id", delivery.getPoId())
                .in("delivery_status", 0, 1));

        if(purchaseOrderItemList == null || purchaseOrderItemList.isEmpty()) {
            return null;
        }

        List<DeliveryItem> deliveryItemList = Lists.newArrayListWithCapacity(purchaseOrderItemList.size());
        //采购明细添加到发货明细
        for (PurchaseOrderItem purchaseOrderItem : purchaseOrderItemList) {
            if (purchaseOrderItem.getQty().equals(purchaseOrderItem.getDeliveredQty())) {
                continue;
            }
            DeliveryItem deliveryItem = new DeliveryItem();
            BeanUtils.copyProperties(purchaseOrderItem, deliveryItem);
            deliveryItem.setDeliveryId(delivery.getId())
                    .setShouldDeliveryQty(purchaseOrderItem.getQty())
                    .setDeliveredQty(purchaseOrderItem.getDeliveredQty())
                    .setQty(purchaseOrderItem.getQty() - purchaseOrderItem.getDeliveredQty())
                    .setPoItemId(purchaseOrderItem.getId())
                    .setOrderQty(purchaseOrderItem.getOrderQty())
                    .setOrderUnit(purchaseOrderItem.getOrderUnit())
                    .setId(null);
            deliveryItemList.add(deliveryItem);
        }
        return deliveryItemList;
    }


    //    @LcnTransaction
    @Override
    public ImportResult excelImport(MultipartFile file) {
        return excelImport(file, null);
    }

    /**
     * 发货单s导入
     */
//    @LcnTransaction
    @Override
    public ImportResult excelImport(MultipartFile file, Map<String, Object> params) {
        return super.excelImport(file, params);
    }

    //    @LcnTransaction
    @Override
    protected ExcelImportResult doExcelImport(MultipartFile multipartFile, Map<String, Object> params) throws Exception {
        ImportParams importParams = PoiUtils.getDefaultImportParams();
        long currentTimeMillis = System.currentTimeMillis();
        ExcelImportResult importResult = PoiUtils.importExcelMore(multipartFile.getInputStream(), DeliveryItemImportDTO.class, importParams);
        log.info("文件加载耗时：{}", DateUtils.formatTime(System.currentTimeMillis() - currentTimeMillis));

        List<DeliveryItemImportDTO> dtoList = Lists.newArrayList(importResult.getList());

        String deliveryId = params.get("deliveryId").toString();
        if (StringUtils.isBlank(deliveryId)) {
            throw new BusinessException("传入参数错误！");
        }

        Delivery delivery = deliveryMapper.selectById(deliveryId);
        if (delivery == null) {
            throw new BusinessException("传入参数错误！");
        }
        List<PurchaseOrderItem> purchaseOrderItems = purchaseOrderItemMapper.selectList(Wrappers.<PurchaseOrderItem>query().eq("po_id", delivery.getPoId()));
        ConcurrentLinkedQueue<DeliveryItem> result = new ConcurrentLinkedQueue();

        DefaultSaveHandler<DeliveryItemImportDTO> saveHandler = new DefaultSaveHandler<DeliveryItemImportDTO>() {
            @Override
            public void doSave(int currentIndex, DeliveryItemImportDTO entity) throws BusinessException {
                Optional<PurchaseOrderItem> optPOItem = purchaseOrderItems.stream().filter(
                        orderItem -> entity.getMaterialName().equalsIgnoreCase(orderItem.getMaterialName())
                                && entity.getMaterialSpec().equalsIgnoreCase(orderItem.getMaterialSpec())).findFirst();
                if (!optPOItem.isPresent()) {
                    log.warn("第{}行耗材{}在采购单中部存在，不进行操作，请注意", currentIndex, entity.getMaterialName());
                    return;
                }

                DeliveryItem deliveryItem = new DeliveryItem();
                PurchaseOrderItem purchaseOrderItem = optPOItem.get();
                Double shouldDeliveryQty = purchaseOrderItem.getQty() - purchaseOrderItem.getDeliveredQty();
                BeanUtils.copyProperties(purchaseOrderItem, deliveryItem);
                deliveryItem.setDeliveryNumber(entity.getDeliveryNumber()).setOrderUnit(entity.getOrderUnit())
                        .setLot(entity.getLot()).setProductionDate(entity.getProductionDate())
                        .setExpiredDate(entity.getExpiredDate()).setSterilizationDate(entity.getSterilizationDate())
                        .setDeliveryId(deliveryId).setPoItemId(purchaseOrderItem.getId()).setShouldDeliveryQty(shouldDeliveryQty).setId(null);
                result.add(deliveryItem);
            }
        };
        BatchSaveTask<DeliveryItem> task = new BatchSaveTask(saveHandler, dtoList);

        this.forkJoinPool.invoke(task);
        this.saveBatch(result);
        return importResult;
    }



    /**
     * @description: 导入字段列表
     **/
    private List<ExportHeadDTO> getExcelHead() {
        List<ExportHeadDTO> exportHeadList = new ArrayList<ExportHeadDTO>();
        ExportHeadDTO headDTO;

        headDTO = new ExportHeadDTO();
        headDTO.setName("materialName").setText("商品名称").setReadonly(true).setCellIndex(0);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("materialSpec").setText("规格").setReadonly(true).setCellIndex(1);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("price").setText("单价(元)").setReadonly(true).setCellIndex(2);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("orderUnit").setText("单位").setReadonly(true).setCellIndex(3);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("deliveredQty").setText("已发").setReadonly(true).setCellIndex(4);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("shouldDeliveryQty").setText("应发").setReadonly(true).setCellIndex(5);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("deliveryNumber").setText("本次发货数量").setCellIndex(6).setRequired(true).setNumber(true);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("lot").setText("批次").setCellIndex(7).setRequired(true);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("productionDate").setText("生产日期").setCellIndex(8).setDate(true).setDatePattern(DateUtils.DEFAULT_PATTER_YMD);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("expiredDate").setText("过期日期").setCellIndex(9).setDate(true).setDatePattern(DateUtils.DEFAULT_PATTER_YMD);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("mfgSn").setText("厂家序号").setCellIndex(10);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("sterilizationDate").setText("灭菌日期").setCellIndex(11);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("udi").setText("商品原厂码(udi)").setCellIndex(12);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("certificateNo").setText("注册证号").setReadonly(true).setCellIndex(13);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("manufacturerName").setText("生产厂商").setReadonly(true).setCellIndex(14);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("deliveryId").setText("发货单标志").setReadonly(true).setCellIndex(15);
        exportHeadList.add(headDTO);

        headDTO = new ExportHeadDTO();
        headDTO.setName("id").setText("发货明细标志").setReadonly(true).setCellIndex(16).setPk(true);
        exportHeadList.add(headDTO);
        return exportHeadList;
    }

    /**
     * @description: 下载导入模板
     **/
    @Override
    public void downloadExcelTemp(HttpServletResponse response, String deliveryId) {
        response.setHeader("content-type", "application/octet-stream");
        response.setContentType("application/octet-stream");
        Delivery delivery =  deliveryMapper.selectById(deliveryId);
        String fileName = StrUtil.format("发货明细_{}_{}.xls",delivery.getCode(),DateUtils.format(DateUtils.now(),DateUtils.YYYYMMDDHHMMSS_PATTER));
        try {
            response.setHeader("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode(fileName, "UTF-8"));
        } catch (UnsupportedEncodingException e2) {
            e2.printStackTrace();
        }

        HSSFWorkbook workbook = new HSSFWorkbook();
        HSSFSheet sheet = workbook.createSheet("发货明细");
        sheet.protectSheet("123456");
        int rowNextNum = 0;

        List<ExportHeadDTO> exportHeadList = getExcelHead();
        //表头列-一级
        ExportHeadDTO exportHeadDTO = null;
        HSSFRow row;
        HSSFCell cell;
        HSSFCellStyle cellStyle;
        HSSFFont font;
        HSSFRichTextString richTextString = null;
        HSSFCellStyle cellStyleTitle;
        cellStyleTitle = workbook.createCellStyle();
        //水平居中
        cellStyleTitle.setAlignment(HorizontalAlignment.CENTER);

        font = workbook.createFont();
        //字体大小
        font.setFontHeightInPoints((short) 14);
        font.setBold(true);   //字体加粗
        cellStyleTitle.setFont(font);

        //单元格锁定的样式
        HSSFCellStyle lockstyle = workbook.createCellStyle();
        lockstyle.setLocked(true);

        //单元格锁定的样式
        HSSFCellStyle unlockstyle = workbook.createCellStyle();
        unlockstyle.setLocked(false);
        unlockstyle.setBorderBottom(BorderStyle.THIN); //底部边框
        unlockstyle.setBottomBorderColor(IndexedColors.GREEN.getIndex());//底部边框颜色

        unlockstyle.setBorderTop(BorderStyle.THIN); //底部边框
        unlockstyle.setTopBorderColor(IndexedColors.GREEN.getIndex());//底部边框颜色

        unlockstyle.setBorderLeft(BorderStyle.THIN); //底部边框
        unlockstyle.setLeftBorderColor(IndexedColors.GREEN.getIndex());//底部边框颜色

        unlockstyle.setBorderRight(BorderStyle.THIN); //底部边框
        unlockstyle.setRightBorderColor(IndexedColors.GREEN.getIndex());//底部边框颜色

        row = sheet.createRow(rowNextNum);
        int cellIndex = 0;
        for (int i = 0; i < exportHeadList.size(); i++) {
            exportHeadDTO = exportHeadList.get(i);
            cell = row.createCell(cellIndex);
            richTextString = new HSSFRichTextString(exportHeadDTO.getText());
            cell.setCellValue(richTextString);

            cell.setCellStyle(cellStyleTitle);

            //改行跨列
            if (exportHeadDTO.getColspan() > 1){

                sheet.addMergedRegion(new CellRangeAddress(rowNextNum, rowNextNum, cellIndex, cellIndex+(exportHeadDTO.getColspan()-1)));
                cellIndex+=exportHeadDTO.getColspan();
            }else {
                cellIndex++;
            }

            //cell宽度
            sheet.setColumnWidth(i, (int) (UtilCommon.getStr(exportHeadDTO.getText(), "").getBytes().length * 1.2d * 256 > 12 * 256 ? UtilCommon.getStr(exportHeadDTO.getText(), "").getBytes().length * 1.2d * 256 : 12 * 256));
        }
        rowNextNum++;

        List<DeliveryItem> deliveryItemList = this.baseMapper.selectList(Wrappers.<DeliveryItem>query().eq("delivery_id", deliveryId));
        JSONArray itemListJson = JSONArray.parseArray(JSONArray.toJSONString(deliveryItemList));
        JSONObject itemJson;
        HSSFCell cellData;
        for (Object json : itemListJson) {
            row = sheet.createRow(rowNextNum);
            itemJson = (JSONObject) json;
            for (int i = 0; i < exportHeadList.size(); i++) {
                exportHeadDTO = exportHeadList.get(i);
                String value = itemJson.get(exportHeadDTO.getName()) + "";
                richTextString = new HSSFRichTextString(UtilCommon.getStr(value, ""));
                cellData = row.createCell(i);
                cellData.setCellValue(richTextString);
                if (exportHeadDTO.isReadonly()) {
                    cellData.setCellStyle(lockstyle);
                } else {
                    cellData.setCellStyle(unlockstyle);
                }
            }
            rowNextNum++;
        }

        OutputStream os1 = null;
        FileUtils.mkdirs(resPath + "download");
        String tmpFilePath = resPath + "download/"+fileName;
        File tmpFile = new File(tmpFilePath);
        byte[] buff = new byte[1024];
        BufferedInputStream bis = null;
        OutputStream os2 = null;

        try {
            os1 = new FileOutputStream(tmpFile);
            workbook.write(os1);

            os2 = response.getOutputStream();
            bis = new BufferedInputStream(new FileInputStream(tmpFile));
            int i = bis.read(buff);
            while (i != -1) {
                os2.write(buff, 0, buff.length);
                os2.flush();
                i = bis.read(buff);
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public ImportResult importDtl(MultipartFile file, String deliveryId) {
        FileUtils.mkdirs(resPath + "import");
        Delivery delivery =  deliveryMapper.selectById(deliveryId);
        String fileName = StrUtil.format("发货明细导入_{}_{}.xls",delivery.getCode(),DateUtils.format(DateUtils.now(),DateUtils.YYYYMMDDHHMMSS_PATTER));
        String tmpFilePath = resPath + "import/"+fileName;
        File fileTmp = new File(tmpFilePath);
        try {
            if (!fileTmp.exists()) {
                fileTmp.createNewFile();
            }
            // 底层也是通过io流写入文件file
            FileCopyUtils.copy(file.getBytes(), fileTmp);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        ArrayList<String[]> arrLst = UtilExcelPoi.getListFromXls(fileTmp, 0);//获取第一个sheet页

        List<ExportHeadDTO> exportHeadList = getExcelHead();
        List<String> arrHeadLst = Arrays.asList(arrLst.get(0));
        exportHeadList.stream().filter(tmp -> !tmp.getText().equals(arrHeadLst.get(tmp.getCellIndex()))).findFirst().ifPresent(tmp2 -> {
            BusinessException.throwError("列{}位置错误，请检查excel模板",tmp2.getText());
        });

        String[] arrRow = null;
        DeliveryItem itemImport;
        Map<String,DeliveryItem> itemImportMap= new HashMap<>();
        String value;
        List<String> fieldAdd = Arrays.asList("shouldDeliveryQty");
        for (int nRow = 1; nRow < arrLst.size(); nRow++) {
            arrRow = arrLst.get(nRow);//Excel导数据的每行数据列
            itemImport = new DeliveryItem();
            for(ExportHeadDTO head : exportHeadList.stream().filter(tmp -> !tmp.isReadonly() || tmp.isPk() || fieldAdd.contains(tmp.getName())).collect(Collectors.toList())) {
                value =arrRow[head.getCellIndex()];
                if (head.isRequired() && StringUtils.isBlank(value)) {
                    BusinessException.throwError("第{}行，{}必填，请检查",nRow +1 +"",head.getText());
                }

                if (StringUtils.isNotBlank(value)) {
                    if (head.isNumber() && !NumberUtils.isNumber(value)) {
                        BusinessException.throwError("第{}行，{}格式应为数字，请检查",nRow +1 +"",head.getText());
                    }
                    if (head.isDate() && !DateUtils.isValidDate(value)) {
                        BusinessException.throwError("第{}行，{}格式应为日期，请检查",nRow +1 +"",head.getText());
                    }
                    BeanUtil.setFieldValue(itemImport,head.getName(),value);
                }
            }
            if (itemImport.getDeliveryNumber() > itemImport.getShouldDeliveryQty()) {
                BusinessException.throwError("第{}行，本次发货数量{}大于应发数量{}，请检查",nRow +1 +"",itemImport.getDeliveryNumber()+"",itemImport.getShouldDeliveryQty()+"");
            }
            itemImportMap.put(itemImport.getId(),itemImport);
        }

        List<DeliveryItem> deliveryItemList = this.baseMapper.selectList(Wrappers.<DeliveryItem>query().eq("delivery_id", deliveryId));
        deliveryItemList = deliveryItemList.stream().filter(tmp ->  itemImportMap.keySet().contains(tmp.getId())).collect(Collectors.toList());
        BusinessException.throwErrorIf(ObjectUtil.length(deliveryItemList) == 0,"没有需要保存的数据，请检查");

        deliveryItemList.stream().forEach(item -> {
            item.setDeliveryNumber(itemImportMap.get(item.getId()).getDeliveryNumber());
            item.setQty(UtilNum.mul(item.getDeliveryNumber(), item.getOrderQty()));
            item.setLot(itemImportMap.get(item.getId()).getLot());
            item.setProductionDate(itemImportMap.get(item.getId()).getProductionDate());
            item.setExpiredDate(itemImportMap.get(item.getId()).getExpiredDate());
            item.setMfgSn(itemImportMap.get(item.getId()).getMfgSn());
            item.setSterilizationDate(itemImportMap.get(item.getId()).getSterilizationDate());
            item.setUdi(itemImportMap.get(item.getId()).getUdi());
            item.setSubtotalAmount(getRoundDouble(item.getDeliveryNumber() * item.getPrice()));
        });
        this.updateBatchById(deliveryItemList);
        updateDeliveryAmount(delivery.getId());
        updateDeliveredQty(delivery.getId());
        ImportResult result = new ImportResult();
        return result;
    }

    /**
     * @description: 发货明细拆分
     * @author: Tai
     * @date: 2024/10/15 12:13
     **/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<String> splitDtl(DeliveryItemSplitDTO entity) {
        DeliveryItem deliveryItem = this.getById(entity.getId());
        BusinessException.throwErrorIf(deliveryItem == null, "发货明细不存在，请刷新重试");
        BusinessException.throwErrorIf(deliveryItem.getDeliveryNumber() < 1, "发货明细发货数量不足1，无需拆分，请刷新重试");
        Delivery delivery = deliveryMapper.selectById(deliveryItem.getDeliveryId());
        BusinessException.throwErrorIf(delivery == null, "发货单不存在，请刷新重试");
        BusinessException.throwErrorIf(!DictConsts.STATUS_DELIVERY_UNFILLED.equals(delivery.getStatus()), "发货单非制单状态不可操作，请刷新重试");

        // 不可整除的部分
        int deliveryNumberP = Double.valueOf(Math.floor(deliveryItem.getDeliveryNumber() % entity.getQtyDtl())).intValue() ;
        // 每行发货数量
        int deliveryNumberLine = Double.valueOf(Math.floor(deliveryItem.getDeliveryNumber() / entity.getQtyDtl())).intValue();


        deliveryItem.setDeliveryNumber(deliveryNumberLine + deliveryNumberP).setShouldDeliveryQty(Double.valueOf(deliveryNumberLine + deliveryNumberP));
        deliveryItem.setSubtotalAmount(getRoundDouble(deliveryItem.getQty() * deliveryItem.getPrice()));
        // 发货单品数量
        deliveryItem.setQty(UtilNum.mul(deliveryItem.getDeliveryNumber(), deliveryItem.getOrderQty()));
        updateById(deliveryItem);

        List<DeliveryItem> itemList = new ArrayList<>();
        DeliveryItem deliveryItemOne;
        int deliveryNumberOne;
        for (int lineIndex = 0;lineIndex < entity.getQtyDtl() - 1;lineIndex++){
            deliveryItemOne = new DeliveryItem();
            BeanUtils.copyProperties(deliveryItem,deliveryItemOne);
            deliveryNumberOne = deliveryNumberLine;
            deliveryItemOne.setDeliveryNumber(deliveryNumberOne).setShouldDeliveryQty(Double.valueOf(deliveryNumberOne)).setId(null);

            // 实发数量
            if (deliveryItemOne.getUnit().equals(deliveryItemOne.getOrderUnit())) {
                deliveryItemOne.setQty(Double.valueOf(deliveryItemOne.getDeliveryNumber()));
            } else {
                deliveryItemOne.setQty(UtilNum.mul(deliveryItemOne.getDeliveryNumber(),deliveryItemOne.getOrderQty()));
            }

            deliveryItemOne.setSubtotalAmount(getRoundDouble(deliveryItemOne.getQty() * deliveryItemOne.getPrice()));
            deliveryItemOne.setQty(UtilNum.mul(deliveryItemOne.getDeliveryNumber(), deliveryItemOne.getOrderQty()));
            itemList.add(deliveryItemOne);
        }
        this.saveBatch(itemList);
        return itemList.stream().map(DeliveryItem::getId).collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addBySelect(List<DeliveryItemAddBySelectDTO> children) {
        Delivery delivery = deliveryMapper.selectById(children.get(0).getDeliveryId());
        BusinessException.throwErrorIf(delivery == null, "发货单不存在，请刷新重试");
        BusinessException.throwErrorIf(!DictConsts.STATUS_DELIVERY_UNFILLED.equals(delivery.getStatus()), "发货单非制单状态不可操作，请刷新重试");
        List<String> poItemIdList = children.stream().map(DeliveryItemAddBySelectDTO::getPoItemId).collect(Collectors.toList());

        // 查询出采购订单明细
        List<PurchaseOrderItem> purchaseOrderItemList = purchaseOrderItemMapper.selectList(Wrappers.<PurchaseOrderItem>query()
                .eq("po_id", delivery.getPoId()).orderByDesc("gmt_create").in("id",poItemIdList));
        List<DeliveryItem> deliveryItemList = new ArrayList<>();

        // 采购明细添加到发货明细
        for (PurchaseOrderItem orderItem : purchaseOrderItemList) {
            //  如果数量=发货数量
            if (NumberUtil.equals(orderItem.getDeliveredQty(),orderItem.getQty())) {
                BusinessException.throwError("商品%s已经完全发货，请刷新数据",orderItem.getMaterialName());
            }
            DeliveryItem deliveryItem = new DeliveryItem();
            DeliveryItem deliveryItem2 = new DeliveryItem();
            com.scs.application.core.utils.BeanUtils.copyProperties(orderItem, deliveryItem);
            deliveryItem.setDeliveryId(delivery.getId())
                    .setPoItemId(orderItem.getId())
                    .setShouldDeliveryQty(orderItem.getQty() - orderItem.getDeliveredQty())
                    .setDeliveredQty(orderItem.getDeliveredQty() != null ? orderItem.getDeliveredQty() : 0)
                    .setDeliveryNumber((int) Math.floor((orderItem.getQty() - orderItem.getDeliveredQty()) / orderItem.getOrderQty()))
                    .setOrderQty(deliveryItem.getOrderUnit() == deliveryItem.getUnit() ? 1.0 : deliveryItem.getOrderQty())
                    .setQty(Math.floor((orderItem.getQty() - orderItem.getDeliveredQty()) / orderItem.getOrderQty()) * orderItem.getOrderQty())
                    .setSubtotalAmount(Math.floor((orderItem.getQty() - orderItem.getDeliveredQty()) / orderItem.getOrderQty()) * orderItem.getOrderQty() * orderItem.getPrice())
                    .setRemark(orderItem.getRemark())
                    .setMedicalConsumablesCode(orderItem.getMedicalConsumablesCode())
                    .setId(null);
            deliveryItem.setGmtCreate(orderItem.getGmtCreate());
            //如果订单明细 包装单位不等于单品单位
            if (orderItem.getOrderUnit() != orderItem.getUnit()) {
                //实发数量求余数
                Double a = (orderItem.getQty() - orderItem.getDeliveredQty()) % orderItem.getOrderQty();
                if (a != 0.0) {
                    com.scs.application.core.utils.BeanUtils.copyProperties(deliveryItem, deliveryItem2);
                    deliveryItem2.setOrderUnit(orderItem.getUnit()).setOrderQty(1.0)
                            .setDeliveryNumber(Integer.valueOf(a.intValue()))
                            .setQty(a)
                            .setSubtotalAmount(a * orderItem.getPrice());
                    deliveryItemList.add(deliveryItem2);
                }
            }
            if (deliveryItem.getDeliveryNumber() > 0) {
                deliveryItemList.add(deliveryItem);
            }
        }
        saveBatch(deliveryItemList);

        updateDeliveryAmount(delivery.getId());
        updateDeliveredQty(delivery.getId());
    }

    // 更新发货明细的已发货数量
    @Override
    public void updateDeliveredQty(String deliveryId) {
        List<DeliveryItem> deliveryItemList = this.list(Wrappers.<DeliveryItem>query().eq("delivery_id",deliveryId));
        if (deliveryItemList.isEmpty()) {
            return;
        }

        List<String> poItemIdList = deliveryItemList.stream().map(DeliveryItem::getPoItemId).distinct().collect(Collectors.toList());
        if (poItemIdList.isEmpty()) {
            return;
        }
        Map<String,PurchaseOrderItem> orderItemById = purchaseOrderItemService.list(Wrappers.<PurchaseOrderItem>query().in("id",poItemIdList))
                .stream().collect(Collectors.toMap(PurchaseOrderItem::getId, item -> item));
        BusinessException.throwErrorIf(ObjectUtil.length(poItemIdList) != ObjectUtil.length(orderItemById.keySet()),"订单明细缺失，请联系管理员");

        deliveryItemList.stream().forEach(deliveryItem -> {
            deliveryItem.setDeliveredQty(orderItemById.get(deliveryItem.getPoItemId()).getDeliveredQty());
        });
        this.updateBatchById(deliveryItemList);
    }

    //更新发货金额
    private void updateDeliveryAmount(String deliveryId) {
        Delivery deliveryDb = deliveryMapper.selectById(deliveryId);
        BusinessException.throwErrorIf(deliveryDb == null, "发货单不存在，请刷新重试");
        BusinessException.throwErrorIf(!DictConsts.STATUS_DELIVERY_UNFILLED.equals(deliveryDb.getStatus()), "发货单非制单状态不可操作，请刷新重试");
        //更新发货单已发货数量
        Delivery delivery = new Delivery();
        delivery.setDeliveryAmount(getDeliveryAmount(deliveryId)).setId(deliveryId);
        deliveryMapper.updateById(delivery);

        // 更新采购明细已发货数量
        purchaseOrderItemService.updateDeliveredQty(deliveryDb.getPoId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveOrUpdate(DeliveryItem entity) {
        super.saveOrUpdate(entity);
        updateDeliveryAmount(entity.getDeliveryId());
        updateDeliveredQty(entity.getDeliveryId());
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean removeCascadeBatchByIds(Collection<? extends Serializable> idList) {
        List<DeliveryItem> itemList = (List<DeliveryItem>) this.listByIds(idList);
        List<String> deliveryIdList = itemList.stream().map(DeliveryItem::getDeliveryId).distinct().collect(Collectors.toList());
        super.removeCascadeBatchByIds(idList);
        deliveryIdList.forEach(deliveryId -> {
            updateDeliveryAmount(deliveryId);
            updateDeliveredQty(deliveryId);
        });
        return true;
    }
}
